/******************************************************************************************************
Copyright (C) 2020 Mestrelab Research S.L. All rights reserved.

This file is part of the Mnova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
/*globals Application, Dir, File, FileDialog, MessageBox, MnUi, nmr, Peak, Peaks, ProgressDialog, settings, TextStream */
/*jslint indent: 4, maxerr: 50, plusplus: true, bitwise: true */

function importTopSpinPeakList() {
	'use strict';

	var activeSpectrum, file, fileKey, fileName, openDir, stream, topSpinPeaks, xml;

	function getPeaksFromXML(aXml) {

		var begin, element, end, labelLenght, peak, peaksArray, searchElementBegin, searchElementEnd, mark, markPosition, tag, tagValue;

		peaksArray = [];
		searchElementBegin = new RegExp("<Peak[12]D", 'g');
		searchElementEnd = "/>";
		mark = '"';
		labelLenght = 7;

		while (aXml.length && aXml.search(searchElementBegin) !== -1) {

			peak = {};
			begin = aXml.search(searchElementBegin);
			begin = begin + labelLenght;
			end = aXml.indexOf(searchElementEnd);

			element = aXml.slice(begin, end);
			element = element.replace("&lt;", "<");
			element = element.replace("&gt;", ">");
			element = element.replace(new RegExp("&amp;", 'g'), "&");

			element = element.replace(/\s+/g, '');

			while (element.length && element.indexOf(mark) !== -1) {
				markPosition = element.indexOf(mark);
				tag = element.slice(0, markPosition - 1);
				element = element.substring(markPosition + 1);
				markPosition = element.indexOf(mark);
				tagValue = element.slice(0, markPosition);
				element = element.substring(markPosition + 1);
				peak[tag] = tagValue;
			}
			peaksArray.push(peak);

			aXml = aXml.substring(aXml.indexOf(searchElementEnd) + searchElementEnd.length);
		}
		return peaksArray;
	}

	function addPeaksToSpectrum(aPeaksArray) {

		var i, addedPeaksCount, discardedPeaksCount, peak, peakIsCompatible, peakF1Ppm, peakF2Ppm, peakType, peaks, progressDialog, topSpinPeak, topSpinPeakTypes, topSpinTotalPeaks;

		topSpinPeakTypes = {
			Unknown: -1,
			Automatic: 0,
			Manual: 1,
			Imported: 2,
			Deconvolution: 3,
			Projected: 4,
			Solvent: 5,
			Impurity: 6,
			Noise: 7
		};

		addedPeaksCount = 0;
		discardedPeaksCount = 0;
		topSpinTotalPeaks = aPeaksArray.length;
		progressDialog = new ProgressDialog();
		progressDialog.showCancelButton = true;
		progressDialog.minimum = 1;
		progressDialog.maximum = topSpinTotalPeaks;
		progressDialog.value = 1;
		progressDialog.show();

		peaks = new Peaks(activeSpectrum.peaks());
		nmr.beginModification(activeSpectrum);

		for (i = 0; i < topSpinTotalPeaks; ++i) {
			topSpinPeak = aPeaksArray[i];
			progressDialog.labelText = "Processing TopSpin peak {0} of {1}".replace('{0}', i + 1).replace('{1}', topSpinTotalPeaks);
			progressDialog.value = i + 1;
			if (topSpinPeak.hasOwnProperty("F1")) {
				peakF1Ppm = parseFloat(topSpinPeak.F1);
				peakIsCompatible = true;
				if (topSpinPeak.hasOwnProperty("F2") && activeSpectrum.dimCount === 2) {
					peakF2Ppm = parseFloat(topSpinPeak.F2);
					peak = new Peak(peakF1Ppm, peakF2Ppm, activeSpectrum);
				} else if (!topSpinPeak.hasOwnProperty("F2") && activeSpectrum.dimCount === 1) {
					peak = new Peak(peakF1Ppm, activeSpectrum);
				} else {
					discardedPeaksCount++;
					peakIsCompatible = false;
				}
				if (peakIsCompatible) {
					if (topSpinPeak.hasOwnProperty("type")) {
						peakType = parseInt(topSpinPeak.type, 10);
						switch (peakType) {
						case topSpinPeakTypes.Unknown:
							peak.type = Peak.Types.Artifact;
							break;
						case topSpinPeakTypes.Automatic:
							peak.type = Peak.Types.Compound;
							break;
						case topSpinPeakTypes.Manual:
							peak.type = Peak.Types.Compound;
							break;
						case topSpinPeakTypes.Imported:
							peak.type = Peak.Types.Compound;
							break;
						case topSpinPeakTypes.Deconvolution:
							peak.type = Peak.Types.Compound;
							break;
						case topSpinPeakTypes.Projected:
							peak.type = Peak.Types.Compound;
							break;
						case topSpinPeakTypes.Solvent:
							peak.type = Peak.Types.Solvent;
							break;
						case topSpinPeakTypes.Impurity:
							peak.type = Peak.Types.Impurity;
							break;
						case topSpinPeakTypes.Noise:
							peak.type = Peak.Types.Artifact;
							break;
						default:
							peak.type = Peak.Types.Compound;
						}
					}
					addedPeaksCount++;
					peaks.append(peak);
				}
			}
			if (progressDialog.wasCanceled) {
				return;
			}
		}
		activeSpectrum.setPeaks(peaks);
		progressDialog.close();
		if (discardedPeaksCount > 0) {
			MessageBox.information("{0} TopSpin peaks were discarded because they are not compatible with the dimension of the active spectrum.".replace('{0}', discardedPeaksCount));
		}
		if (addedPeaksCount > 0) {
			MessageBox.information("{0} TopSpin peaks were succesfully added to the active spectrum.".replace('{0}', addedPeaksCount));
		} else {
			MessageBox.information("No TopSpin peaks were added to the active spectrum.");
		}
		activeSpectrum.setPeaks(peaks);
		nmr.endModification(activeSpectrum);
		activeSpectrum.update();
	}

	/* check if there is an active spectrum */
	activeSpectrum = nmr.activeSpectrum();
	if (!activeSpectrum.isValid()) {
		MessageBox.critical("No active NMR spectrum found in current document");
		return;
	}

	/* get file name */
	fileKey = "Import TopSpin Peak List/File";
	openDir = settings.value(fileKey, Dir.home());
	fileName = FileDialog.getOpenFileName("TopSpin peak list (*.xml)", "Select File", openDir);
	if (fileName === "") {
		return;
	}
	settings.setValue(fileKey, fileName);

	/* open file and get contents */
	file = new File(fileName);
	if (!file.exists || !file.open(File.ReadOnly)) {
		MessageBox.critical("Error opening file");
		return;
	}
	stream = new TextStream(file);
	xml = stream.readAll();

	/* add peaks in file to spectrum */
	topSpinPeaks = getPeaksFromXML(xml);
	addPeaksToSpectrum(topSpinPeaks);
}

if (this.MnUi && MnUi.scripts_nmr) {
	MnUi.scripts_nmr.scripts_nmr_ImportTopSpinPeakList = importTopSpinPeakList;
}